package dao

import (
	"context"

	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"

	"goldtree/internal/entity"
)

// StockDao 股票数据访问对象
type StockDao struct{}

var Stock = StockDao{}

// Insert 插入股票信息
func (dao *StockDao) Insert(ctx context.Context, data *entity.Stock) (int64, error) {
	// 构建插入数据，排除ID字段让数据库自动生成
	insertData := g.Map{
		"code":         data.Code,
		"name":         data.Name,
		"market":       data.Market,
		"industry":     data.Industry,
		"sector":       data.Sector,
		"market_cap":   data.MarketCap,
		"pe_ratio":     data.PeRatio,
		"pb_ratio":     data.PbRatio,
		"listing_date": data.ListingDate,
		"is_active":    data.IsActive,
		"created_at":   g.DB().Raw("datetime('now')"),
		"updated_at":   g.DB().Raw("datetime('now')"),
	}

	result, err := g.DB().Model("stocks").Ctx(ctx).Data(insertData).Insert()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

// Update 更新股票信息
func (dao *StockDao) Update(ctx context.Context, id int, data *entity.Stock) error {
	_, err := g.DB().Model("stocks").Ctx(ctx).Where("id", id).Update(data)
	return err
}

// UpdateByCode 根据股票代码更新
func (dao *StockDao) UpdateByCode(ctx context.Context, code string, data *entity.Stock) error {
	_, err := g.DB().Model("stocks").Ctx(ctx).Where("code", code).Update(data)
	return err
}

// Delete 删除股票信息
func (dao *StockDao) Delete(ctx context.Context, id int) error {
	_, err := g.DB().Model("stocks").Ctx(ctx).Where("id", id).Delete()
	return err
}

// GetById 根据ID获取股票信息
func (dao *StockDao) GetById(ctx context.Context, id int) (*entity.Stock, error) {
	var stock *entity.Stock
	err := g.DB().Model("stocks").Ctx(ctx).Where("id", id).Scan(&stock)
	return stock, err
}

// GetByCode 根据股票代码获取股票信息
func (dao *StockDao) GetByCode(ctx context.Context, code string) (*entity.Stock, error) {
	var stock *entity.Stock
	err := g.DB().Model("stocks").Ctx(ctx).Where("code", code).Scan(&stock)
	return stock, err
}

// GetList 获取股票列表
func (dao *StockDao) GetList(ctx context.Context, page, limit int, condition ...interface{}) ([]*entity.Stock, error) {
	var stocks []*entity.Stock
	query := g.DB().Model("stocks").Ctx(ctx)

	if len(condition) > 0 {
		query = query.Where(condition[0], condition[1:]...)
	}

	err := query.Page(page, limit).OrderDesc("id").Scan(&stocks)
	return stocks, err
}

// GetCount 获取股票总数
func (dao *StockDao) GetCount(ctx context.Context, condition ...interface{}) (int, error) {
	query := g.DB().Model("stocks").Ctx(ctx)

	if len(condition) > 0 {
		query = query.Where(condition[0], condition[1:]...)
	}

	return query.Count()
}

// Search 搜索股票
func (dao *StockDao) Search(ctx context.Context, keyword string, page, limit int) ([]*entity.Stock, error) {
	var stocks []*entity.Stock
	err := g.DB().Model("stocks").Ctx(ctx).
		Where("code LIKE ? OR name LIKE ?", "%"+keyword+"%", "%"+keyword+"%").
		Page(page, limit).
		OrderDesc("id").
		Scan(&stocks)
	return stocks, err
}

// GetByMarket 根据市场获取股票列表
func (dao *StockDao) GetByMarket(ctx context.Context, market string, page, limit int) ([]*entity.Stock, error) {
	var stocks []*entity.Stock
	err := g.DB().Model("stocks").Ctx(ctx).
		Where("market", market).
		Page(page, limit).
		OrderDesc("id").
		Scan(&stocks)
	return stocks, err
}

// GetByIndustry 根据行业获取股票列表
func (dao *StockDao) GetByIndustry(ctx context.Context, industry string, page, limit int) ([]*entity.Stock, error) {
	var stocks []*entity.Stock
	err := g.DB().Model("stocks").Ctx(ctx).
		Where("industry", industry).
		Page(page, limit).
		OrderDesc("id").
		Scan(&stocks)
	return stocks, err
}

// BatchInsert 批量插入股票
func (dao *StockDao) BatchInsert(ctx context.Context, stocks []*entity.Stock) error {
	// 构建批量插入数据，排除ID字段
	batchData := make([]g.Map, 0, len(stocks))

	for _, stock := range stocks {
		insertData := g.Map{
			"code":         stock.Code,
			"name":         stock.Name,
			"market":       stock.Market,
			"industry":     stock.Industry,
			"sector":       stock.Sector,
			"market_cap":   stock.MarketCap,
			"pe_ratio":     stock.PeRatio,
			"pb_ratio":     stock.PbRatio,
			"listing_date": stock.ListingDate,
			"is_active":    stock.IsActive,
			"created_at":   g.DB().Raw("datetime('now')"),
			"updated_at":   g.DB().Raw("datetime('now')"),
		}
		batchData = append(batchData, insertData)
	}

	_, err := g.DB().Model("stocks").Ctx(ctx).Data(batchData).Insert()
	return err
}

// IsCodeExists 检查股票代码是否存在
func (dao *StockDao) IsCodeExists(ctx context.Context, code string) (bool, error) {
	count, err := g.DB().Model("stocks").Ctx(ctx).Where("code", code).Count()
	return count > 0, err
}

// GetActiveStocks 获取有效股票列表
func (dao *StockDao) GetActiveStocks(ctx context.Context, page, limit int) ([]*entity.Stock, error) {
	var stocks []*entity.Stock
	err := g.DB().Model("stocks").Ctx(ctx).
		Where("is_active", true).
		Page(page, limit).
		OrderDesc("id").
		Scan(&stocks)
	return stocks, err
}

// GetIndustryList 获取行业列表
func (dao *StockDao) GetIndustryList(ctx context.Context) ([]string, error) {
	var industries []string
	err := g.DB().Model("stocks").Ctx(ctx).
		Fields("DISTINCT industry").
		Where("industry != ''").
		OrderAsc("industry").
		Scan(&industries)
	return industries, err
}

// GetMarketList 获取市场列表
func (dao *StockDao) GetMarketList(ctx context.Context) ([]string, error) {
	var markets []string
	err := g.DB().Model("stocks").Ctx(ctx).
		Fields("DISTINCT market").
		Where("market != ''").
		OrderAsc("market").
		Scan(&markets)
	return markets, err
}

// Transaction 事务处理
func (dao *StockDao) Transaction(ctx context.Context, fn func(ctx context.Context, tx gdb.TX) error) error {
	return g.DB().Transaction(ctx, fn)
}

// GetListWithSort 获取带排序的股票列表
func (dao *StockDao) GetListWithSort(ctx context.Context, page, limit int, sortBy, sortOrder string, condition ...interface{}) ([]*entity.Stock, error) {
	var stocks []*entity.Stock
	query := g.DB().Model("stocks").Ctx(ctx)

	if len(condition) > 0 {
		query = query.Where(condition[0], condition[1:]...)
	}

	// 添加排序
	if sortOrder == "desc" {
		query = query.OrderDesc(sortBy)
	} else {
		query = query.OrderAsc(sortBy)
	}

	err := query.Page(page, limit).Scan(&stocks)
	return stocks, err
}

// GetMarketStatistics 获取市场统计
func (dao *StockDao) GetMarketStatistics(ctx context.Context) (map[string]int, error) {
	result := make(map[string]int)

	type MarketStat struct {
		Market string `json:"market"`
		Count  int    `json:"count"`
	}

	var stats []*MarketStat
	err := g.DB().Model("stocks").Ctx(ctx).
		Fields("market, COUNT(*) as count").
		Where("market != ''").
		Group("market").
		Scan(&stats)

	if err != nil {
		return nil, err
	}

	for _, stat := range stats {
		result[stat.Market] = stat.Count
	}

	return result, nil
}

// GetIndustryStatistics 获取行业统计
func (dao *StockDao) GetIndustryStatistics(ctx context.Context) (map[string]int, error) {
	result := make(map[string]int)

	type IndustryStat struct {
		Industry string `json:"industry"`
		Count    int    `json:"count"`
	}

	var stats []*IndustryStat
	err := g.DB().Model("stocks").Ctx(ctx).
		Fields("industry, COUNT(*) as count").
		Where("industry != ''").
		Group("industry").
		OrderDesc("count").
		Limit(20). // 只返回前20个行业
		Scan(&stats)

	if err != nil {
		return nil, err
	}

	for _, stat := range stats {
		result[stat.Industry] = stat.Count
	}

	return result, nil
}

// GetMarketCapRanges 获取市值区间统计
func (dao *StockDao) GetMarketCapRanges(ctx context.Context) (map[string]int, error) {
	result := make(map[string]int)

	// 小盘股: 小于50亿
	smallCap, err := g.DB().Model("stocks").Ctx(ctx).
		Where("market_cap > 0 AND market_cap < ?", 5000000000).
		Count()
	if err != nil {
		return nil, err
	}
	result["小盘股(<50亿)"] = smallCap

	// 中盘股: 50亿-200亿
	midCap, err := g.DB().Model("stocks").Ctx(ctx).
		Where("market_cap >= ? AND market_cap < ?", 5000000000, 20000000000).
		Count()
	if err != nil {
		return nil, err
	}
	result["中盘股(50-200亿)"] = midCap

	// 大盘股: 大于200亿
	largeCap, err := g.DB().Model("stocks").Ctx(ctx).
		Where("market_cap >= ?", 20000000000).
		Count()
	if err != nil {
		return nil, err
	}
	result["大盘股(>200亿)"] = largeCap

	return result, nil
}

// GetTopByMarketCap 获取市值最大的股票
func (dao *StockDao) GetTopByMarketCap(ctx context.Context, limit int) ([]*entity.Stock, error) {
	var stocks []*entity.Stock
	err := g.DB().Model("stocks").Ctx(ctx).
		Where("market_cap > 0").
		OrderDesc("market_cap").
		Limit(limit).
		Scan(&stocks)
	return stocks, err
}

// GetSectorList 获取板块列表
func (dao *StockDao) GetSectorList(ctx context.Context) ([]string, error) {
	var sectors []string
	err := g.DB().Model("stocks").Ctx(ctx).
		Fields("DISTINCT sector").
		Where("sector != ''").
		OrderAsc("sector").
		Scan(&sectors)
	return sectors, err
}

// UpdateMarketData 更新市场数据
func (dao *StockDao) UpdateMarketData(ctx context.Context, code string, marketCap, peRatio, pbRatio float64) error {
	data := g.Map{
		"market_cap": marketCap,
		"pe_ratio":   peRatio,
		"pb_ratio":   pbRatio,
		"updated_at": g.DB().Raw("datetime('now')"),
	}
	_, err := g.DB().Model("stocks").Ctx(ctx).Where("code", code).Data(data).Update()
	return err
}

// GetActiveStockCodes 获取所有有效股票代码
func (dao *StockDao) GetActiveStockCodes(ctx context.Context) ([]string, error) {
	var codes []string
	err := g.DB().Model("stocks").Ctx(ctx).
		Fields("code").
		Where("is_active = ?", true).
		Scan(&codes)
	return codes, err
}

// BulkUpdateStatus 批量更新股票状态
func (dao *StockDao) BulkUpdateStatus(ctx context.Context, codes []string, isActive bool) error {
	data := g.Map{
		"is_active":  isActive,
		"updated_at": g.DB().Raw("datetime('now')"),
	}
	_, err := g.DB().Model("stocks").Ctx(ctx).Where("code IN (?)", codes).Data(data).Update()
	return err
}
